package model

import (
	"encoding/json"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"iot-base/auth/db"
	"iot-base/auth/utils"
	"time"
)

var (
	PresetsKey = "presets#thingId#"
	Null       = "Null"
)

type (
	PresetModel struct {
		db    *gorm.DB
		redis *db.RedisCli
	}

	Presets struct {
		Model
		ThingId     string `gorm:"type:varchar(40);index;not null;" json:"thing_id"`
		PresetName  string `gorm:"type:varchar(40);not null"json:"preset_name"`
		PresetToken string `gorm:"type:varchar(3)" json:"preset_token"`
	}
)

func NewPresetModel(gormDb *gorm.DB) *PresetModel {
	return &PresetModel{
		db:    gormDb,
		redis: db.NewRedis(),
	}
}

func (m *PresetModel) GetPresetFinds(thingId string) ([]Presets, error) {
	presets := make([]Presets, 0)
	key := fmt.Sprintf(PresetsKey+"%v", thingId)
	strList, _ := m.redis.Get(key)
	if strList != "" {
		if strList == Null {
			return presets, nil
		}
		err := json.Unmarshal([]byte(strList), &presets)
		if err != nil {
			return presets, nil
		}
		return append([]Presets{}, presets...), err
	}

	tx := m.db.Where("thing_id = ?", thingId).Find(&presets)
	// 避免缓存穿透.
	if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
		m.redis.Set(key, Null, time.Second*3)
		return presets, nil
	}
	if tx.Error != nil {
		return presets, tx.Error
	}

	strJson, err := utils.StructToJson(presets)
	if err != nil {
		return presets, err
	}
	m.redis.Set(key, strJson, time.Minute*15)
	return append([]Presets{}, presets...), nil
}

func (m *PresetModel) AddPreset(insetData *Presets) error {
	key := fmt.Sprintf(PresetsKey+"%v", insetData.ThingId)
	m.redis.Del(key)
	return m.db.Create(insetData).Error
}

func (m *PresetModel) UpdatePreset(insetData *Presets) (int64, error) {
	key := fmt.Sprintf(PresetsKey+"%v", insetData.ThingId)
	m.redis.Del(key)
	tx := m.db.Where("thing_id = ?", insetData.ThingId).Where("preset_token = ?", insetData.PresetToken).Updates(insetData)
	return tx.RowsAffected, tx.Error
}

func (m *PresetModel) FindPreset(thingId, presetToken string) (Presets, error) {
	var preset Presets
	err := m.db.Where("thing_id = ?", thingId).Where("preset_token = ?", presetToken).First(&preset).Error
	return preset, err
}

func (m *PresetModel) DelPreset(thingId, presetsToken string) (int64, error) {
	key := fmt.Sprintf(PresetsKey+"%v", thingId)
	m.redis.Del(key)
	tx := m.db.Where("thing_id = ?", thingId).Where("preset_token = ?", presetsToken).Delete(&Presets{})
	return tx.RowsAffected, tx.Error
}
